package com.xms.sdk.client;

import com.xms.core.enums.AccessRightValue;
import com.xms.core.enums.OperationStage;
import com.xms.core.enums.OperationType;
import com.xms.core.exception.XmsException;
import com.xms.plugin.service.IEntityPluginExecutor;
import com.xms.schema.entity.Attribute;
import com.xms.schema.service.attribute.IAttributeFinderService;
import com.xms.sdk.core.query.ConditionOperator;
import com.xms.sdk.core.query.QueryExpression;
import com.xms.sdk.event.EntitySharedEvent;
import com.xms.sdk.event.EntitySharingEvent;
import com.xms.sdk.service.IDataFinder;
import com.xms.sdk.service.IDataSharer;
import com.xms.security.entity.PrincipalObjectAccess;
import com.xms.utils.CollectionUtil;
import com.xms.utils.UUIDUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.UUID;

/**
 * <p>
 * DataSharer
 * </p>
 *
 * @author migo
 * @since 2021/9/29
 */
@Service
public class DataSharer extends DataProviderBase implements IDataSharer {
    private IAttributeFinderService _attributeFinderService;
    private IDataFinder _dataFinder;
    private IEntityPluginExecutor _entityPluginExecutor;
    @Autowired
    public DataSharer(
            IAttributeFinderService attributeFinderService,
            IDataFinder dataFinder,
            IEntityPluginExecutor entityPluginExecutor)
    {
        _attributeFinderService = attributeFinderService;
        _dataFinder = dataFinder;
        _entityPluginExecutor = entityPluginExecutor;
    }

    @Override
    public boolean share(UUID entityId, UUID recordId, List<PrincipalObjectAccess> principals) throws XmsException {
        return this.share(entityId, recordId, principals, false);
    }

    @Override
    public boolean share(UUID entityId, UUID recordId, List<PrincipalObjectAccess> principals, boolean ignorePermissions) throws XmsException {
        try
        {
            com.xms.schema.entity.Entity entityMetadata = _entityFinderService.getById(entityId);
            QueryExpression query = new QueryExpression(entityMetadata.getName());
            query.ColumnSet.AllColumns = true;
            query.Criteria.addCondition(entityMetadata.getName() + "id", ConditionOperator.Equal, recordId);
            com.xms.core.data.Entity entity = _dataFinder.retrieve(query);
            if (!ignorePermissions)
            {
                verifyEntityPermission(entity, AccessRightValue.Share, entityMetadata);
            }
            List<Attribute> attributeMetadatas = _attributeFinderService.getByEntityId(entityMetadata.getEntityid());
            internalOnShare(entity, OperationStage.PreOperation, entityMetadata, attributeMetadatas, principals);
            _principalObjectAccessService.deleteByObjectId(entityId, recordId);
            if (CollectionUtil.notEmpty(principals))
            {
                for (PrincipalObjectAccess item : principals)
                {
                    item.setPrincipalobjectaccessid(UUIDUtil.get());
                }
                _principalObjectAccessService.saveBatch(principals);
            }
            internalOnShare(entity, OperationStage.PostOperation, entityMetadata, attributeMetadatas, principals);
            return true;
        }
        catch (Exception e)
        {
            return onException(e);
        }
    }

    /**
     * 共享记录时触发的事件
     * @param data
     * @param stage
     * @param entityMetadata
     * @param attributeMetadatas
     */
    private void internalOnShare(com.xms.core.data.Entity data, OperationStage stage, com.xms.schema.entity.Entity entityMetadata, List<com.xms.schema.entity.Attribute> attributeMetadatas, List<PrincipalObjectAccess> principals) throws Exception {
        //plugin
        _entityPluginExecutor.execute(OperationType.Share, stage, data, entityMetadata, attributeMetadatas);
        publishEvents(data, stage, entityMetadata, principals);
    }

    // 发布事件
    private void publishEvents(com.xms.core.data.Entity data, OperationStage stage, com.xms.schema.entity.Entity entityMetadata, List<PrincipalObjectAccess> principals)
    {
        if (stage == OperationStage.PreOperation)
        {
            _eventPublisher.publish(new EntitySharingEvent(data, entityMetadata, principals));
        }
        else if (stage == OperationStage.PostOperation)
        {
            _eventPublisher.publish(new EntitySharedEvent(data, entityMetadata, principals));
        }
    }
}
